/*================================================================================
*
*
*
*
*
* 项目名称:20200614SDRAM
* 文件名称: SDRAM.c
* 创建日期: 2020Jun 15, 2020
* 文件描述:
*
================================================================================*/
#include "SDRAM.h"
#include "fmc.h"

//-private define-----------------------------------------------------------------
#define TEST_BYTES_NUM        (1024*1024*8) //8MB

//-private data-------------------------------------------------------------------
uint8_t u8Arr[TEST_BYTES_NUM]__attribute__((at(0xD0000000))); //测试用数组

//-private code-------------------------------------------------------------------
static uint8_t u8SDRAM_SendCmd(uint8_t u8Bank,uint8_t u8Cmd, uint8_t u8Refresh, uint16_t u16RegVal);
static void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t nCount);
static void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t nCount);

/*
 * @brief SDRAM W9825G6KH-6 Device 初始化
 * @param hsdram sdram句柄
 * @rtval
 */
void SDRAM_Init(SDRAM_HandleTypeDef *hsdram)
{
  uint32_t temp=0;
  uint32_t i=0;

  u8SDRAM_SendCmd(1,  FMC_SDRAM_CMD_CLK_ENABLE, 1, 0); //时钟配置使能
  for(i=0; i<80000; i++); //延时，至少大于200us
  u8SDRAM_SendCmd(1,  FMC_SDRAM_CMD_PALL, 1, 0); //堆所有存储区预充电
  u8SDRAM_SendCmd(1, FMC_SDRAM_CMD_AUTOREFRESH_MODE, 4, 0); //自刷新次数

  //模式寄存器定义
  temp = SDRAM_MODEREG_BURST_LENGTH_2 |
         SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
         SDRAM_MODEREG_CAS_LATENCY_3 |
         SDRAM_MODEREG_OPERATING_MODE_STANDARD |
         SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
  u8SDRAM_SendCmd(1, FMC_SDRAM_CMD_LOAD_MODE, 1, temp);

  HAL_SDRAM_ProgramRefreshRate(hsdram, 824);
}


/*
 * @brief 根据SDRAM模式配置FMC_SDCMR
 * @param u8Bank, 0：BANK5 1:BANK6
 * @param u8Cmd, 指令
 * @param u8Refresh, 自刷新次数
 * @param u16RegVal, 模式寄存器的定义
 * @rtval 0：正常，1：失败
 */
static uint8_t u8SDRAM_SendCmd(uint8_t u8Bank,uint8_t u8Cmd, uint8_t u8Refresh, uint16_t u16RegVal)
{
  uint32_t u32TarBank=0;
  FMC_SDRAM_CommandTypeDef SDRAM_Cmd;

  if(u8Bank==0)
    u32TarBank = FMC_SDRAM_CMD_TARGET_BANK1;
  else
    u32TarBank = FMC_SDRAM_CMD_TARGET_BANK2;

  SDRAM_Cmd.CommandMode = u8Cmd; //命令
  SDRAM_Cmd.CommandTarget = u32TarBank; //目标SDRAM存储区域
  SDRAM_Cmd.AutoRefreshNumber = u8Refresh; //自刷新次数
  SDRAM_Cmd.ModeRegisterDefinition = u16RegVal; //要写入模式寄存器的值

  if(HAL_SDRAM_SendCommand(&hsdram1, &SDRAM_Cmd, 0x1000)==HAL_OK)
    return 0;
  else
    return 1;
}

/*
 * @brief 向SDRAM写入一定数量字节，按1个字节写入
 * @param pBuffer 待写入SDRAM数据
 * @param WriteAddr SDRAM相对地址
 * @param nCount  需要写入的字节数
 * @rtval void
 */
static void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t nCount)
{
  while(nCount--)
  {
    *(uint8_t *)(SDRAM_BANK2_ADR+WriteAddr) = *pBuffer;
    WriteAddr++;
    pBuffer++;
  }
}

/*
 * @brief 向SDRAM读取一定数量字节，按1个字节读取
 * @param pBuffer 待读取SDRAM数据缓冲
 * @param WriteAddr SDRAM相对地址
 * @param nCount  需要读取的字节数
 * @rtval void
 */
static void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t nCount)
{
  while(nCount--)
  {
    *pBuffer++ = *(uint8_t *)(SDRAM_BANK2_ADR+ReadAddr);
    ReadAddr++;
  }
}

/*
 * breif 测试SDRAM读写
 * @param
 * @rtval 1:操作成功 0：操作失败
 */
uint8_t SDRAM_Test_Process(void)
{
  uint32_t i=0;
  uint8_t u8TestVal=0x5A, u8Tmp=0;
  uint8_t l_u8Rtn=0;

  for(i=0; i<8*1024*1024; i=i+4*1024) //写每隔16K字节空间2048个数据
  {
    *(uint8_t *)(SDRAM_BANK2_ADR+i) = u8TestVal;
  }

  for(i=0; i<8*1024*1024; i=i+4*1024)
  {
    u8Tmp = *(uint8_t *)(SDRAM_BANK2_ADR+i);

    if(u8Tmp!=u8TestVal)
    {
      l_u8Rtn = 0;

      return l_u8Rtn;
    }

    u8Tmp = 0;
  }
  l_u8Rtn = 1;

  return l_u8Rtn;
}
